/**
 * @author yuan<cihang.yuan@happyelements.com>
 * @since 1.7
 */
package commons.base.http;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.TimeZone;

import javax.servlet.Servlet;
import javax.servlet.ServletContext;

import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;


/**
 * jetty server
 * @author yuan<cihang.yuan@happyelements.com>
 * @since 1.7
 */
public class JettyHttpServer {

	private Server server;
	/** 最小线程数 */
	private int minThreadPoolSize;
	/** 最大线程数 */
	private int maxThreadPoolSize;
	private InetSocketAddress socketAddress;
	/** 线程池 */
	private QueuedThreadPool threadPool;
	/** 是否debug模式 */
	private boolean debug = false;
	private ServletContextHandler handler = new ServletContextHandler(null, "/");
	
	public JettyHttpServer(){
		this(8080);
	}
	
	public JettyHttpServer(int port){
		int minThreadPoolSize = Runtime.getRuntime().availableProcessors() * 5;
		int maxThreadPoolSize = Runtime.getRuntime().availableProcessors() * 100;
		
		init(minThreadPoolSize, maxThreadPoolSize, new InetSocketAddress(port));
	}
	
	public JettyHttpServer(int minThreadPoolSize, int maxThreadPoolSize, String host, int port) {
		init(minThreadPoolSize, maxThreadPoolSize, new InetSocketAddress(host, port));
	}
	
	private void init(int minThreadPoolSize, int maxThreadPoolSize, InetSocketAddress socketAddress){
		this.minThreadPoolSize = minThreadPoolSize;
		this.maxThreadPoolSize = maxThreadPoolSize;
		this.socketAddress = socketAddress;
	}
	
	public void addServlet(String path, Class<? extends Servlet> servlet){
		handler.addServlet(servlet, path);
	}
	
	public void addServlet(ServletHolder servlet, String pathSpec){
		handler.addServlet(servlet, pathSpec);
	}
	
	public void setAttribute(String name, Object value){
		handler.setAttribute(name, value);
	}
	
	public void setClassLoader(ClassLoader cl){
		handler.setClassLoader(cl);
	}
	
	public void setInitParameter(String name, String value){
		handler.setInitParameter(name, value);
	}
	
	public ServletContext getServletContext(){
		return handler.getServletContext();
	}

	public void setDebug(boolean debug) {
		this.debug = debug;
	}

	/**
	 * 启动
	 * @throws Exception
	 */
	public void start() throws Exception{
		if(server == null){
			// 初始化线程池
			if(threadPool == null){
				threadPool = new QueuedThreadPool();
		    	threadPool.setMinThreads(minThreadPoolSize);
		        threadPool.setMaxThreads(maxThreadPoolSize);
//		        threadPool.setMaxIdleTimeMs(30000);
			}
			
			server = new Server(socketAddress);
			// 设置连接相关参数
			setConnector();
	        server.addBean(threadPool);
	        
	        if(debug){
	        	// request log
		        server.addBean(createRequestLog());
			}
	        
	        // 支持gzip, 默认超过256个字节压缩
	        handler.setHandler(new GzipHandler());
	        
	        server.setHandler(handler);
	        
	        server.setStopAtShutdown(true);
//	        server.setSendServerVersion(true);
//	        server.setSendDateHeader(true);
//	        server.setGracefulShutdown(1000);
	        
	        server.start();
		}
	}
	
	private RequestLog createRequestLog() throws IOException{
		if(!new File("./logs").getCanonicalFile().exists()){
			new File("./logs").getCanonicalFile().mkdirs();
		}
		NCSARequestLog requestLog = new NCSARequestLog("./logs/yyyy_mm_dd.request.log");
        requestLog.setFilenameDateFormat("yyyy_MM_dd");
        requestLog.setLogTimeZone(TimeZone.getDefault().getID());
        
        return requestLog;
	}
	
	/**
	 * 设置连接相关参数
	 */
	private void setConnector(){
//		SelectChannelConnector connector = (SelectChannelConnector)server.getConnectors()[0];
//		connector.setMaxIdleTime(300000);
//		connector.setAcceptors(2);
//		connector.setStatsOn(false);
//		connector.setLowResourcesConnections(20000);
//		connector.setLowResourcesMaxIdleTime(5000);
	}
	
	public void join() throws InterruptedException{
		if(server != null){
			server.join();
		}
	}
	
	/**
	 * 停服
	 */
	public void stop(){
		if(server != null){
			try {
				server.stop();
			} catch (Exception e) {
				throw new RuntimeException(e.getMessage(), e);
			}
			server = null;
		}
		
		if(threadPool != null){
			try {
				threadPool.stop();
			} catch (Exception e) {
				throw new RuntimeException(e.getMessage(), e);
			}
			threadPool = null;
		}
	}
}
